using Aspire.Domain;
using Aspire.Domain.Core;
using Aspire.Mapper;
using Aspire.Repository;

using Microsoft.AspNetCore.Mvc;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Aspire.Application
{
    /// <summary>
    /// 应用服务
    /// </summary>
    [ApiController]
    [Route("[controller]/[action]")]
    public class AppService : ControllerBase
    {
        protected List<string> ErrorList = new List<string>();

        protected void NotifyErrors(params string[] errors)
        {
            ErrorList.AddRange(errors);
        }

        protected void ThrowBaseError(StatusCodesEnum status, string title, params string[] errors)
        {
            throw new ResponseException(status, title, errors.Concat(ErrorList).ToArray());
        }

        protected void ThrowNotFind(string title = "没有找到任何数据!", params string[] errors)
        {
            ThrowBaseError(StatusCodesEnum.Status410Gone, title, errors);
        }
    }

    /// <summary>
    /// 增删改查(增改一体)
    /// </summary>
    /// <typeparam name="TEntity">数据实体</typeparam>
    /// <typeparam name="TOutputDto">输出Dto</typeparam>
    /// <typeparam name="TCreateOrUpdateInputDto">创建或更新Dto</typeparam>
    public class CurdAppService<TEntity, TOutputDto, TCreateOrUpdateInputDto> : CurdAppService<long, TEntity, TOutputDto, TCreateOrUpdateInputDto>
        where TEntity : BaseEntity<long>
    {
        public CurdAppService(IRepository<long, TEntity> repository, IMap map) : base(repository, map) { }
    }

    /// <summary>
    /// 增删改查(增改一体)
    /// </summary>
    /// <typeparam name="TId">Id, 用于执行Id(删除, 更新, 获取等)操作</typeparam>
    /// <typeparam name="TEntity">数据实体</typeparam>
    /// <typeparam name="TOutputDto">输出Dto</typeparam>
    /// <typeparam name="TCreateOrUpdateInputDto">创建或更新Dto</typeparam>
    public class CurdAppService<TId, TEntity, TOutputDto, TCreateOrUpdateInputDto> : BaseCurdServiceAsync<TId, TEntity, TOutputDto, TCreateOrUpdateInputDto, TCreateOrUpdateInputDto>
        where TEntity : BaseEntity<TId>
    {
        private readonly IRepository<TId, TEntity> _repository;
        private readonly IMap _map;

        public CurdAppService(IRepository<TId, TEntity> repository, IMap map) : base(repository, map)
        {
            _repository = repository;
            _map = map;
        }

        [HttpPost("/[controller]/{id?}")]
        public virtual async Task<TOutputDto> CreateOrUpdateAsync(TId id, [FromBody] TCreateOrUpdateInputDto input)
        {
            TEntity r;
            if (id.Equals(default(TId)))
            {
                TEntity t = _map.To<TEntity>(input);
                r = await _repository.AddThenEntityAsync(t);
            }
            else
            {
                TEntity o = await _repository.GetByIdAsync(id);
                _map.To(input, o);
                r = await _repository.UpdateThenEntityAsync(o);
            }
            return _map.To<TOutputDto>(r);
        }
    }

    /// <summary>
    /// 增删改查(搜索)
    /// </summary>
    /// <typeparam name="TId">Id, 用于执行Id(删除, 更新, 获取等)操作</typeparam>
    /// <typeparam name="TEntity">数据实体</typeparam>
    /// <typeparam name="TOutputDto">输出Dto</typeparam>
    /// <typeparam name="TCreateInputDto">创建Dto</typeparam>
    /// <typeparam name="TUpdateInputDto">更新Dto</typeparam>
    /// <typeparam name="TSearchInputDto">搜索Dto</typeparam>
    public class CurdAppService<TId, TEntity, TOutputDto, TCreateInputDto, TUpdateInputDto, TSearchInputDto> : CurdAppService<TId, TEntity, TOutputDto, TCreateInputDto, TUpdateInputDto>
        where TEntity : BaseEntity<TId>
        where TSearchInputDto : SearchInputDto
    {
        private readonly IRepository<TId, TEntity> _repository;
        public CurdAppService(IRepository<TId, TEntity> repository, IMap map) : base(repository, map)
        {
            _repository = repository;
        }

        [HttpPost]
        public virtual IEnumerable<TOutputDto> SearchAsync([FromBody] TSearchInputDto input)
        {
            throw new NotImplementedException();
        }

        public override IEnumerable<KeyValuePair<string, object>> GetDtoProperties(string type)
        {
            type = type.ToLower();
            switch (type)
            {
                case "create":
                //return ViewModuleHelper.GetFormFieldsByDtoType(typeof(TSearchInputDto));
                default:
                    return base.GetDtoProperties(type);
            }
        }
    }

    /// <summary>
    /// 增删改查
    /// </summary>
    /// <typeparam name="TId">Id, 用于执行Id(删除, 更新, 获取等)操作</typeparam>
    /// <typeparam name="TEntity">数据实体</typeparam>
    /// <typeparam name="TOutputDto">输出Dto</typeparam>
    /// <typeparam name="TCreateInputDto">创建Dto</typeparam>
    /// <typeparam name="TUpdateInputDto">更新Dto</typeparam>
    public class CurdAppService<TId, TEntity, TOutputDto, TCreateInputDto, TUpdateInputDto> : BaseCurdServiceAsync<TId, TEntity, TOutputDto, TCreateInputDto, TUpdateInputDto>
        where TEntity : BaseEntity<TId>
    {
        private readonly IRepository<TId, TEntity> _repository;
        private readonly IMap _map;

        public CurdAppService(IRepository<TId, TEntity> repository, IMap map) : base(repository, map)
        {
            _repository = repository;
            _map = map;
        }

        [HttpPost("/[controller]")]
        public virtual async Task<TOutputDto> CreateAsync([FromBody] TCreateInputDto input)
        {
            TEntity e = _map.To<TEntity>(input);
            TEntity r = await _repository.AddThenEntityAsync(e);
            return _map.To<TOutputDto>(r);
        }

        [HttpPut("/[controller]/{id}")]
        public virtual async Task<TOutputDto> UpdateAsync(TId id, [FromBody] TUpdateInputDto input)
        {
            TEntity o = await _repository.GetByIdAsync(id);
            _map.To(input, o);
            TEntity r = await _repository.UpdateThenEntityAsync(o);
            return _map.To<TOutputDto>(r);
        }
    }

    /// <summary>
    /// 增删改查(基类)
    /// </summary>
    /// <typeparam name="TId">Id, 用于执行Id(删除, 更新, 获取等)操作</typeparam>
    /// <typeparam name="TEntity">数据实体</typeparam>
    /// <typeparam name="TOutputDto">输出Dto</typeparam>
    /// <typeparam name="TCreateInputDto">创建Dto</typeparam>
    /// <typeparam name="TUpdateInputDto">更新Dto</typeparam>
    public abstract class BaseCurdServiceAsync<TId, TEntity, TOutputDto, TCreateInputDto, TUpdateInputDto> : AppService
        where TEntity : BaseEntity<TId>
    {
        private readonly IRepository<TId, TEntity> _repository;
        private readonly IMap _map;

        public BaseCurdServiceAsync(IRepository<TId, TEntity> repository, IMap map)
        {
            _repository = repository;
            _map = map;
        }

        [HttpDelete("/[controller]/{id}")]
        public virtual async Task<bool> DeleteAsync(TId id)
            => await _repository.DeleteAsync(id);

        [HttpGet("/[controller]/{id}")]
        public virtual async Task<TOutputDto> GetAsync(TId id)
        {
            TEntity r = await _repository.GetByIdAsync(id);
            return _map.To<TOutputDto>(r);
        }

        [HttpGet("/[controller]/[action]/{type}")]
        public virtual IEnumerable<KeyValuePair<string, object>> GetDtoProperties(string type)
        {
            type = type.ToLower();
            switch (type)
            {
                case "create":
                //return ViewModuleHelper.GetFormFieldsByDtoType(typeof(TCreateInputDto));
                case "update":
                //return ViewModuleHelper.GetFormFieldsByDtoType(typeof(TUpdateInputDto));
                case "output":
                //return ViewModuleHelper.GetFormFieldsByDtoType(typeof(TOutputDto));
                default:
                    ThrowNotFind(errors: $"请求的数据内容: {type}");
                    return null;
            }
        }
    }
}
